﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
using Newtonsoft.Json.Linq;

namespace DidaManager.Models.JsonConvert
{
    public class Hj212ServerToDownloadFile
    {
        [JsonPropertyName("HJ212Options")]
        public Hj212Options HJ212Options { get; set; } = new Hj212Options();

        [JsonPropertyName("HttpSamplerOption")]
        public HttpSamplerOption HttpSamplerOption { get; set; } = new HttpSamplerOption();

        [JsonPropertyName("Recorder")]
        public Recorder Recorder { get; set; } = new Recorder();

        [JsonPropertyName("HMI")]
        public Hmi HMI { get; set; } = new Hmi();

        [JsonPropertyName("Log")]
        public Log Log { get; set; } = new Log();

        public static Hj212ServerToDownloadFile ParseFromJson(string filePath)
        {
            if (!File.Exists(filePath))
            {
                throw new FileNotFoundException($"文件不存在: {filePath}");
            }

            string jsonString = File.ReadAllText(filePath);
            if (string.IsNullOrWhiteSpace(jsonString))
            {
                throw new ArgumentException("JSON内容不能为空");
            }

            var options = new JsonSerializerOptions
            {
                PropertyNameCaseInsensitive = true
            };

            return JsonSerializer.Deserialize<Hj212ServerToDownloadFile>(jsonString, options) ?? new Hj212ServerToDownloadFile();
        }

        public static void SaveToJson(Hj212ServerToDownloadFile config, string filePath)
        {
            string jsonContent = JsonSerializer.Serialize(config, JsonSerializerOptionsManager.Compact);
            File.WriteAllText(filePath, jsonContent, new UTF8Encoding(false));
        }

        // ========== 以下为数据库JSON -> 下载格式的转换 ==========

        /// <summary>
        /// 从数据库JSON解析，转换为下载格式，并保存为 *_download.json
        /// </summary>
        public static void ParseDbJsonAndSave(string filePath)
        {
            if (!File.Exists(filePath))
            {
                throw new FileNotFoundException($"文件不存在: {filePath}");
            }

            string jsonContent = File.ReadAllText(filePath);
            if (string.IsNullOrWhiteSpace(jsonContent))
            {
                throw new ArgumentException("JSON内容不能为空");
            }

            var jsonObject = JObject.Parse(jsonContent);
            var dbConfig = MapJsonToObject<DatabaseHj212Config>(jsonObject);
            var downloadConfig = ConvertToDownloadFormat(dbConfig);
            SaveToJson(downloadConfig, filePath);
        }

        private static Hj212ServerToDownloadFile ConvertToDownloadFormat(DatabaseHj212Config db)
        {
            var result = new Hj212ServerToDownloadFile();

            // ST from systemType: take content before ':'
            var st = db.SystemType;
            if (!string.IsNullOrWhiteSpace(st))
            {
                int idx = st.IndexOf(':');
                if (idx >= 0)
                {
                    st = st.Substring(0, idx);
                }
                st = st.Trim();
            }
            if (string.IsNullOrWhiteSpace(st)) st = "21";

            result.HJ212Options.ST = st;
            result.HJ212Options.MinIntervalMin = ToInt(db.ReportInterval, 1);

            // Servers
            var servers = new List<DatabaseHj212Server?> { db.Server1, db.Server2, db.Server3 };
            foreach (var s in servers)
            {
                if (s == null) continue;
                var server = new Hj212Server
                {
                    Enabled = s.Enabled,
                    ServerUri = BuildServerUri(s.Ip, s.Port),
                    ServerPort = ToInt(s.Port, 502),
                    MN = s.Mn,
                    PW = s.Pw,
                    ProtocolVersion = s.ProtocolVersion,
                    HeartbeatIntervalS = ToInt(s.HeartbeatInterval, 30),
                    RtdIntervalS = ToInt(s.RealtimeReportInterval, 30),
                    Timeout = ToInt(s.Timeout, 10),
                    RetryCnt = ToInt(s.RetryCount, 3),
                    MinuteReportEnabled = s.MinuteReportEnabled,
                    MinuteReportInterval = s.MinuteReportInterval,
                    HourReportEnabled = s.HourReportEnabled,
                    DayReportEnabled = s.DayReportEnabled
                };
                result.HJ212Options.Servers.Add(server);
            }

            // Other sections
            result.HttpSamplerOption.Url = db.HttpSampleOption ?? string.Empty;
            result.HMI.SerialPort = db.Hmi ?? string.Empty;

            result.Recorder.RecorderType = "sqlite";

            // Log level: db.Level may be string number
            result.Log.Level = ToInt(db.Level, 6);
            result.Log.OutputPath.Add("file");
            result.Log.OutputPath.Add("stdout");

            return result;
        }

        private static string BuildServerUri(string? ip, string? port)
        {
            ip = ip?.Trim() ?? string.Empty;
            port = port?.Trim() ?? string.Empty;
            if (string.IsNullOrWhiteSpace(ip)) return string.Empty;
            if (string.IsNullOrWhiteSpace(port)) return ip;
            return $"tcp://{ip}:{port}";
        }

        private static int ToInt(string? s, int defaultValue)
        {
            if (int.TryParse(s, out int v)) return v;
            return defaultValue;
        }

        // 反射映射（参考其它类实现）
        private static T MapJsonToObject<T>(JObject json) where T : class, new()
        {
            var obj = new T();
            var properties = typeof(T).GetProperties();
            foreach (var prop in properties)
            {
                var jsonName = GetJsonPropertyName(prop);
                if (json.TryGetValue(jsonName, out JToken? value) && value != null)
                {
                    SetPropertyValue(obj, prop, value);
                }
            }
            return obj;
        }

        private static string GetJsonPropertyName(PropertyInfo prop)
        {
            var attr = prop.GetCustomAttribute<JsonPropertyNameAttribute>();
            return attr?.Name ?? prop.Name;
        }

        private static void SetPropertyValue(object obj, PropertyInfo prop, JToken value)
        {
            if (obj == null) throw new ArgumentNullException(nameof(obj)); // Ensure obj is not null

            try
            {
                if (prop.PropertyType == typeof(string))
                {
                    prop.SetValue(obj, value.ToString());
                    return;
                }
                if (prop.PropertyType == typeof(int))
                {
                    prop.SetValue(obj, value.Type == JTokenType.Integer ? value.Value<int>() : ToInt(value.ToString(), 0));
                    return;
                }
                if (prop.PropertyType == typeof(bool))
                {
                    if (value.Type == JTokenType.Boolean)
                    {
                        prop.SetValue(obj, value.Value<bool>());
                    }
                    else
                    {
                        bool.TryParse(value.ToString(), out bool b);
                        prop.SetValue(obj, b);
                    }
                    return;
                }
                if (prop.PropertyType.IsClass && prop.PropertyType != typeof(string))
                {
                    if (value is JObject nested)
                    {
                        var nestedObj = Activator.CreateInstance(prop.PropertyType);
                        foreach (var nestedProp in prop.PropertyType.GetProperties())
                        {
                            var name = GetJsonPropertyName(nestedProp);
                            if (nested.TryGetValue(name, out var nv) && nv != null)
                            {
                                if (nestedObj != null)
                                {
                                    SetPropertyValue(nestedObj, nestedProp, nv);
                                }
                            }
                        }
                        prop.SetValue(obj, nestedObj);
                    }
                    return;
                }
            }
            catch
            {
                // ignore and leave default
            }
        }
    }

    public class Hj212Options
    {
        [JsonPropertyName("Servers")]
        public List<Hj212Server> Servers { get; set; } = new List<Hj212Server>();

        [JsonPropertyName("ST")]
        public string ST { get; set; } = string.Empty;

        [JsonPropertyName("MinIntervalMin")]
        public int MinIntervalMin { get; set; }
    }

    public class Hj212Server
    {
        [JsonPropertyName("Enabled")]
        public bool Enabled { get; set; }

        [JsonPropertyName("ServerUri")]
        public string ServerUri { get; set; } = string.Empty;

        [JsonPropertyName("port")]
        public int ServerPort { get; set; }

        [JsonPropertyName("MN")]
        public string MN { get; set; } = string.Empty;

        [JsonPropertyName("PW")]
        public string PW { get; set; } = string.Empty;

        [JsonPropertyName("ProtocolVersion")]
        public string ProtocolVersion { get; set; } = string.Empty;

        [JsonPropertyName("HeartbeatIntervalS")]
        public int HeartbeatIntervalS { get; set; }

        [JsonPropertyName("RtdIntervalS")]
        public int RtdIntervalS { get; set; }

        [JsonPropertyName("Timeout")]
        public int Timeout { get; set; }

        [JsonPropertyName("RetryCnt")]
        public int RetryCnt { get; set; }

        [JsonPropertyName("MinuteReportEnabled")]
        public bool MinuteReportEnabled { get; set; }

        [JsonPropertyName("MinuteReportInterval")]
        public string MinuteReportInterval { get; set; } = "3";

        [JsonPropertyName("HourReportEnabled")]
        public bool HourReportEnabled { get; set; }

        [JsonPropertyName("DayReportEnabled")]
        public bool DayReportEnabled { get; set; }

    }

    public class HttpSamplerOption
    {
        [JsonPropertyName("Url")]
        public string Url { get; set; } = string.Empty;
    }

    public class Recorder
    {
        [JsonPropertyName("RecorderType")]
        public string RecorderType { get; set; } = string.Empty;
    }

    public class Hmi
    {
        [JsonPropertyName("SerialPort")]
        public string SerialPort { get; set; } = string.Empty;
    }

    public class Log
    {
        [JsonPropertyName("Level")]
        public int Level { get; set; }

        [JsonPropertyName("OutputPath")]
        public List<string> OutputPath { get; set; } = new List<string>();
    }

    // ========== 数据库JSON结构定义 ==========

    public class DatabaseHj212Config
    {
        [JsonPropertyName("systemType")]
        public string SystemType { get; set; } = string.Empty;

        [JsonPropertyName("reportInterval")]
        public string ReportInterval { get; set; } = "1";

        [JsonPropertyName("httpSampleOption")]
        public string HttpSampleOption { get; set; } = string.Empty;

        [JsonPropertyName("hmi")]
        public string Hmi { get; set; } = string.Empty;

        [JsonPropertyName("level")]
        public string Level { get; set; } = "6";

        [JsonPropertyName("server1")]
        public DatabaseHj212Server? Server1 { get; set; }

        [JsonPropertyName("server2")]
        public DatabaseHj212Server? Server2 { get; set; }

        [JsonPropertyName("server3")]
        public DatabaseHj212Server? Server3 { get; set; }
    }

    public class DatabaseHj212Server
    {
        [JsonPropertyName("enabled")]
        public bool Enabled { get; set; }

        [JsonPropertyName("ip")]
        public string? Ip { get; set; }

        [JsonPropertyName("port")]
        public string? Port { get; set; }

        [JsonPropertyName("mn")]
        public string Mn { get; set; } = string.Empty;

        [JsonPropertyName("pw")]
        public string Pw { get; set; } = string.Empty;

        [JsonPropertyName("protocolVersion")]
        public string ProtocolVersion { get; set; } = string.Empty;

        [JsonPropertyName("heartbeatInterval")]
        public string HeartbeatInterval { get; set; } = "30";

        [JsonPropertyName("realtimeReportInterval")]
        public string RealtimeReportInterval { get; set; } = "30";

        [JsonPropertyName("timeout")]
        public string Timeout { get; set; } = "10";

        [JsonPropertyName("retryCount")]
        public string RetryCount { get; set; } = "3";

        [JsonPropertyName("minuteReportEnabled")]
        public bool MinuteReportEnabled { get; set; }

        [JsonPropertyName("minuteReportInterval")]
        public string MinuteReportInterval { get; set; } = "3";

        [JsonPropertyName("hourReportEnabled")]
        public bool HourReportEnabled { get; set; }

        [JsonPropertyName("dayReportEnabled")]
        public bool DayReportEnabled { get; set; }
    }
}
